from django.core.cache import cache
from django.conf import settings
from functools import wraps
import hashlib
import json
import logging

logger = logging.getLogger(__name__)


def make_cache_key(*args, **kwargs):
    """生成缓存键"""
    key_data = {
        'args': args,
        'kwargs': sorted(kwargs.items())
    }
    key_string = json.dumps(key_data, sort_keys=True, default=str)
    return hashlib.md5(key_string.encode()).hexdigest()


def cache_result(timeout=300, key_prefix=''):
    """缓存装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = f"{key_prefix}:{func.__name__}:{make_cache_key(*args, **kwargs)}"
            
            # 尝试从缓存获取结果
            result = cache.get(cache_key)
            if result is not None:
                logger.debug(f"Cache hit for key: {cache_key}")
                return result
            
            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            cache.set(cache_key, result, timeout)
            logger.debug(f"Cache set for key: {cache_key}")
            
            return result
        return wrapper
    return decorator


class CacheManager:
    """缓存管理器"""
    
    @staticmethod
    def get_user_permissions(user_id):
        """获取用户权限（带缓存）"""
        cache_key = f"user_permissions:{user_id}"
        permissions = cache.get(cache_key)

        if permissions is None:
            from rbac.models import Permission
            permissions = list(Permission.objects.filter(
                role__users__id=user_id
            ).select_related().values_list('code', flat=True).distinct())
            cache.set(cache_key, permissions, 3600)  # 缓存1小时

        return permissions
    
    @staticmethod
    def get_user_roles(user_id):
        """获取用户角色（带缓存）"""
        cache_key = f"user_roles:{user_id}"
        roles = cache.get(cache_key)

        if roles is None:
            from rbac.models import Role
            roles = list(Role.objects.filter(
                users__id=user_id, is_active=True
            ).values_list('code', flat=True))
            cache.set(cache_key, roles, 3600)  # 缓存1小时

        return roles
    
    @staticmethod
    def get_user_menus(user_id):
        """获取用户菜单（带缓存）"""
        cache_key = f"user_menus:{user_id}"
        menus = cache.get(cache_key)
        
        if menus is None:
            from rbac.models import Menu
            from rbac.serializers import MenuSerializer
            
            # 获取用户可访问的菜单
            accessible_menus = Menu.objects.filter(
                permissions__role__users__id=user_id,
                is_active=True,
                parent=None
            ).distinct().order_by('sort_order')
            
            serializer = MenuSerializer(accessible_menus, many=True)
            menus = serializer.data
            cache.set(cache_key, menus, 1800)  # 缓存30分钟
        
        return menus
    
    @staticmethod
    def invalidate_user_cache(user_id):
        """清除用户相关缓存"""
        cache_keys = [
            f"user_permissions:{user_id}",
            f"user_roles:{user_id}",
            f"user_menus:{user_id}"
        ]
        cache.delete_many(cache_keys)
        logger.info(f"Invalidated cache for user {user_id}")
    
    @staticmethod
    def invalidate_role_cache(role_id):
        """清除角色相关缓存"""
        from rbac.models import User
        # 获取拥有该角色的所有用户
        user_ids = User.objects.filter(roles__id=role_id).values_list('id', flat=True)
        
        for user_id in user_ids:
            CacheManager.invalidate_user_cache(user_id)
        
        logger.info(f"Invalidated cache for role {role_id}")
    
    @staticmethod
    def invalidate_permission_cache(permission_id):
        """清除权限相关缓存"""
        from rbac.models import User
        # 获取拥有该权限的所有用户
        user_ids = User.objects.filter(
            roles__permissions__id=permission_id
        ).values_list('id', flat=True).distinct()
        
        for user_id in user_ids:
            CacheManager.invalidate_user_cache(user_id)
        
        logger.info(f"Invalidated cache for permission {permission_id}")


# 缓存装饰器的便捷函数
def cache_for_5_minutes(func):
    return cache_result(timeout=300, key_prefix='5min')(func)

def cache_for_1_hour(func):
    return cache_result(timeout=3600, key_prefix='1hour')(func)

def cache_for_1_day(func):
    return cache_result(timeout=86400, key_prefix='1day')(func)
